package com.itheima.mq.rabbitmq;

import com.itheima.mq.rabbitmq.producer.RabbitmqProducer;
import com.itheima.mq.rabbitmq.producer.RabbitmqSendMsgConfirm;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

/**
 * 启动类
 */
@SpringBootApplication
public class ProducerApplication {
    
    // 发送消息的模板类
    private static RabbitTemplate rabbitTemplate;
    
    public static void main(String[] args) {
        
        // 启动程序
        ConfigurableApplicationContext applicationContext = SpringApplication.run(ProducerApplication.class, args);
        rabbitTemplate = applicationContext.getBean(RabbitTemplate.class);
        // 查看AMQP协议生产者消息流转过程
        // producerMessageTransport();
        //
        // 测试FanoutExchange交换机的消息发送
        // fanoutExchangeMessageTransport();
        
        // 测试Direct类型的交换机
        // directExchangeMessageTransport();
        
        // 测试Topic类型的交换机的消息发送
        // topicExchangeMessageTransport();
        
        // 测试headers交换机的消息发送
        // headersExchangeMessageTransport();
        
        // 设置消息ttl,包括消息队列的统一过期时间,和消息单独的过期时间,消息过期后就会被丢弃
        // sendPreMessageTTL();
        // sendMessage2TTLQueue();
        //死信队列测试
        // sendMessage2DLXExchange();
        
        //持久化测试
        // presistentMessageTransport();
        
        //测试事务消息
        // sendTransactionManagerMsg(applicationContext);
        
        //    发送消息publisher confirm
        sendPublisherConfirmMsg(applicationContext);
        
        //发送消息给集群镜像队列
        // clusterQueueMessage();
    }
    
    // 测试Direct类型的交换机
    private static void clusterQueueMessage() {
        rabbitTemplate.convertAndSend("direct.exchange",
                "cluster", "测试 cluster queue data");
    }
    
    //事务消息不用,因为性能过低
    //事务机制会影响Rabbitmq的性能，事务机制在一条消息发送之后会使发送端阻塞，以等待RabbitmqMQ的
    // 回应，之后才能继续发送下一条消息。因此在真实开发过程中很少的使用。
    private static void
    sendTransactionManagerMsg(ConfigurableApplicationContext
                                      applicationContext) {
        RabbitmqProducer rabbitmqProducer =
                applicationContext.getBean(RabbitmqProducer.class);
        try {
            rabbitmqProducer.sendMessage();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("事务消息回滚了");
        }
    }
    
    //这个是发送端的publish confirm 和return ack的合集
    private static void
    sendPublisherConfirmMsg(ConfigurableApplicationContext
                                    applicationContext) {
        RabbitmqSendMsgConfirm rabbitmqSendMsgConfirm =
                applicationContext.getBean(RabbitmqSendMsgConfirm.class);
        
        rabbitmqSendMsgConfirm.sendMsg("这个是publisher confirm 消息"
                , "direct.exchange", "create");
    }
    
    private static void presistentMessageTransport() {
        rabbitTemplate.convertAndSend("direct.exchange",
                "create", "direct exchange 测试数据",
                (message) -> {
                    // spring boot和rabbitmq整合以后，默认消息是会被持久化的，我们可以将消息    的持久化方式设置为不进行持久化
                    message.getMessageProperties()
                            .setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT);
                    return message;
                });
    }
    
    /**
     * 测试发送消息时候,发送消息的过期时间ttl
     */
    private static void sendPreMessageTTL() {
        MessagePostProcessor messagePostProcessor = new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                MessageProperties messageProperties = message.getMessageProperties();
                //设置消息属性对象
                messageProperties.setExpiration("30000");
                return message;
            }
        };
        rabbitTemplate.convertAndSend("direct.exchange",
                "create", "测试延迟发送,为每一个消息设置过期时间"
                , messagePostProcessor);
    }    // 测试Direct类型的交换机
    
    //发送消息给设置了过期时间的队列
    private static void sendMessage2TTLQueue() {
        rabbitTemplate.convertAndSend("direct.exchange", "ttl", "direct exchange 测试数据");
    }
    
    //发送消息给死信队列
    private static void sendMessage2DLXExchange() {
        rabbitTemplate.convertAndSend("direct.exchange", "dlx",
                "死信队列消息测试");
    }
    
    // 测试headers交换机的消息发送
    private static void headersExchangeMessageTransport() {
        String message = "headers exchanges message";
        MessageProperties messageProperties = new MessageProperties();
        // messageProperties.setHeader("key1" , "value1");
        messageProperties.setHeader("key2", "value2");
        Message obj = new Message(message.getBytes(), messageProperties);
        rabbitTemplate.convertAndSend("headers.exchange", "", obj);
    }
    
    private static void zhzHeadersExchangeMessageTransport() {
        MessageProperties properties = new MessageProperties();
        properties.setHeader("key2", "value2");
        Message obj = new Message("headers exchanges message".getBytes(), properties);
        rabbitTemplate.convertAndSend("headers.exchange", "", obj);
    }
    
    // 测试Topic类型的交换机的消息发送
    private static void topicExchangeMessageTransport() {
        
        // routingKey: topic.email.queue  ---> topic.email
        // routingKey: topic.sms.queue  ---> topic.sms
        // routingKey: topic.email.sms  ---> topic.email && topic.sms
        rabbitTemplate.convertAndSend("topic.exchange", "topic.sms.queue", "topic exchange 测试数据");
        rabbitTemplate.convertAndSend("topic.exchange", "topic.email.queue", "topic exchange 测试数据");
        rabbitTemplate.convertAndSend("topic.exchange", "topic.email.sms", "topic exchange 测试数据");
    }
    
    // 测试Direct类型的交换机
    private static void directExchangeMessageTransport() {
        rabbitTemplate.convertAndSend("direct.exchange", "delete", "direct exchange 测试数据");
        rabbitTemplate.convertAndSend("direct.exchange", "create", "direct exchange 测试数据");
    }
    
    // 测试FanoutExchange交换机的消息发送
    private static void fanoutExchangeMessageTransport() {
        rabbitTemplate.convertAndSend("fanout.exchange", "itheima", "fanout exchange 测试数据");
    }
    
    // 查看AMQP协议生产者消息流转过程测试代码
    private static void producerMessageTransport() {
        //测试amqp协议生产者消息
        rabbitTemplate.convertAndSend("fanout.exchange", "", "rabbitmq生产者消息流程过程测试");
    }
    
}

